#coding=utf-8
# Create your views here.
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import render_to_response
from release.citylife.models import User, DoubanSubject, Job, Bid
from douban.service import DoubanService
from douban.client import OAuthClient
import urllib
from xmlnode import XMLNode
from django.core.exceptions import ObjectDoesNotExist
from django import forms
import StringIO
from PIL import Image
import hashlib
import os
from django.core.files import File
import lxml.html as H
import time

import logging
logging.basicConfig()
log = logging.getLogger(__name__)
formatter = logging.Formatter('%(asctime)s, %(filename)s, %(lineno)d: %(message)s')
s_hdlr = logging.StreamHandler()
s_hdlr.setFormatter(formatter)
f_hdlr = logging.FileHandler('media/citylife/log.txt')
f_hdlr.setFormatter(formatter)
log.addHandler(s_hdlr)
log.addHandler(f_hdlr)
log.setLevel(logging.INFO)

class GV:
    MATCH_DIMENTION = 10
    PAGE_LENGTH = 10
    top_tags = [u'管理经济学', u'经济', u'金融', u'商业', u'投资', u'营销', u'广告', u'理财', u'股票', u'创业', u'企业史', u'策划', u'口译', u'实战口译', u'英语', u'翻译', u'英语学习', u'interpretation', u'学习', u'林超伦']

def home(request):
    import thread
    #thread.start_new_thread(test, ())
    test()
    return HttpResponse('......')

def test():    
    populate_db()
    update()
    calCoordination()
    friend_recommend()
    book_recommend()
    group_recommend()
    

##### facilities * #####
def safe_print(s):
    import types
    t = type(s)
    if t == types.ListType:
        for x in s:
            if type(x) == types.UnicodeType:
                print x.encode('gbk', 'ignore')
            else:
                print x
    elif t == types.DictionaryType:
        for (key, value) in dic.items():
            print key.encode('gbk', 'ignore'), value        
    elif t == types.UnicodeType:
        print x.encode('gbk', 'ignore')
    else:
        try:
            print s
        except Exception, e:
            print 'cannot print. error=%s' % e

def drop_tag(e, tag):
    """
    input:
        e: HtmlElement
        tag_to_drop: str
    output:
        e
    Desc: 
        a wrap up of the drop_tag method lxml.htmlelement.drop_tag. remove all the tags of [tag] from e
    """
    _tags = e.findall(tag)
    if(len(_tags)):
        for _tag in _tags:
            _tag.drop_tag()
    return e


def login_validation(view_func):#decorator method
    def wrapper(*args, **kw):
        request = args[0]
        if not request.session.get('uid'):
            return HttpResponseRedirectAfter('/citylife/login/', 'have to login first')
        return view_func(*args, **kw)
    return wrapper

@login_validation
def authorization(view_func):
    def wrapper(*args, **kw):
        request = args[0]
        uid = request.session.get('uid')
        user = User.objects.get(id = uid)
        if(not (user.douban_access_key and user.douban_access_secret)):
            return HttpRequestRedirect('/citylife/register_import')
        return view_func(*args, **kw)
    return wrapper

def sendDoubanMessage(user, msg):
    """
    send a message [msg] to [user]
    """
    pass
    

def HttpResponseRedirectAfter(url, message, s=3000):
    """
    input:
        url|str
        message|str
        s|int
    desc:
        show [message] and redirect to [url] after [s] ms
    """
    return HttpResponse("""<body onload="javascript:setTimeout(function(){window.location.href='%s'},%d);">%s</body>""" % (url, s, message))

##### facilities #####

##### match * #####
def importSubjectDetail(subject, url):
    """
    add the details of the subject at [url] into [subject]
    """
    import re

    url_opened = False
    for i in range(5):
        try:
            html = urllib.urlopen(url).read().decode('utf8', 'ignore')
            url_opened = True
        except Exception, e:
            log.error('urlopen failed, url=%s, error=%s', url, e)
            time.sleep(3)

    if (url_opened):
        doc = H.document_fromstring(html)
        rating = float(doc.xpath('//strong[@class="ll rating_num"]/text()'))
        rating_count = int(doc.xpath('//p[@class="rating_self font_normal"]/a/text()'))
        tags = doc.xpath('//div[@class="related_info"]/div[@class="blank20"]/div/a/text()')
        tag_counts = [int(c) for c in re.compile('(\d+)').findall(drop_tag(doc.xpath('//div[@class="related_info"]/div[@class="blank20"]/div')[0], 'a').xpath('text()')[0])]

        subject.rating = rating
        subject.rating_count = rating_count
        subject.tags = tags
        subject.tag_counts = tag_counts
    else:
        log.info('urlopen failed, url=%s', url)
    

def importSubjects(user, url):
    """
    add the douban subjects in page [url] into db
    """
    log.info('importSubjects(%s, %s)' % (user.name, url))

    
    url_opened = False

    for i in range(5):
        try:
            html = urllib.urlopen(url).read().decode('utf8', 'ignore')
            url_opened = True
        except Exception, e:
            log.error('urlopen failed, url=%s, error=%s', url, e)
            time.sleep(3)

    if (not url_opened):
        return 0

    doc = H.document_fromstring(html)
    uls = doc.xpath('//div[contains(@class, "article")]/ul[@class="collect tlst"]')

    for ul in uls:
        url = ul.xpath('li/h3/a/@href')[0]
        title = ul.xpath('li/h3/a/text()')[0]
        
        subject, created = DoubanSubject.objects.get_or_create(url = url)
        if created:
            subject.title = title.encode('utf8', 'ignore')
            subject.url = url
            
            importSubjectDetail(subject, url)
            subject.save()

        if subject.id not in user.douban_subject_ids:
            user.douban_subject_ids.append(subject.id)

    return len(uls)

def update():
    log.info('upload()')
    """
    update the info of [user] from douban
    """

    users = User.objects.all()

    for user in users:
        cat1s = ['book']
        cat2s = ['collect','wish','do']
        for cat1 in cat1s:
            for cat2 in cat2s:
                page_index = 1
                url = 'http://%s.douban.com/list/%s/%s' % (cat1, user.douban_id, cat2)
                while(1):
                    if importSubjects(user, url) == 0:
                        break

                    url = 'http://%s.douban.com/list/%s/collect?start=%d&status=%s'%(cat1, user.douban_id, page_index*15, cat2)
                    page_index += 1
        user.save()
    
def calCoordination():
    """
    calculate the coordination of each user
    """

    for user in users:     
        tmp_dic = {}
        for subject_id in user.douban_subject_ids:
            subject = DoubanSubject.objects.get(id = subject_id)
            
            for tag in subject.tags:
                if tag in tmp_dic.keys():
                    tmp_dic[tag] = tmp_dic[tag] + 1
                else:
                    tmp_dic[tag] = 1
        
        #printUnicodeDic(tmp_dic)

        coordination = []
        for top_tag in GV.top_tags:
            if top_tag in tmp_dic.keys():
                coordination.append(tmp_dic[top_tag])
            else:
                coordination.append(0)

        user.coordination = coordination
        user.save()
        
        print "user.coordination", user.coordination

def user_distance(user1, user2):
    c1, c2 = user1.coordination, user2.coordination
    return sum([abs(c1[i]-c2[i]) for i in range(len(c1))])

def friend_recommend():
    """
    update the [matched_user_ids] of each user. First, compute the distance between each pair of users. Then, sorted the distances descending order. The [MATCH_THRESHOLD_RATIO*len(users)]-th distance is used as a threshold. Two users are matched if their distance is less than the threshold.
    """
    log.info('match()')

    users = User.objects.all()
    distance_mat = [[-1 for i in range(len(users))] for j in range(len(users))]
    distances = []
    for u1 in range(len(users)):
        for u2 in range(u1 + 1, len(users)):
            user1, user2 = users[u1], users[u2]
            distance_mat[u1][u2] = user_distance(user1, user2)
            distances.append(distance_mat[u1][u2])
    
    #match_threshold = sorted(distances, reverse = True)[int(GV.MATCH_THRESHOLD_RATIO * len(users))]
    match_threshold = 100
    for u1 in range(len(users)):
        for u2 in range(u1 + 1, len(users)):
            log.info(distance_mat[u1][u2])
            if distance_mat[u1][u2] < match_threshold:
                user1, user2 = users[u1], users[u2]
                user1.matched_user_ids.append(user2.id)
                user2.matched_user_ids.append(user1.id)
    
    #clear the redundant ids
    for u1 in range(len(users)):
        for u2 in range(u1 + 1, len(users)):
            user1, user2 = users[u1], users[u2]
            user1.matched_user_ids = list(set(user1.matched_user_ids))
            user2.matched_user_ids = list(set(user2.matched_user_ids))

    for user in users:
        user.save()

def book_recommend():
    pass

def group_recommend():
    pass
##### match #####


def populate_db():
    for user in User.objects.all():
        user.delete()    

    for subject in DoubanSubject.objects.all():
        subject.delete()

    data_xml = file('media/citylife/users.xml').read()
    node = XMLNode.parseXML(data_xml)

    for user in node.user:
        _user = User(
                name = user.name[0].elementText, 
                email = user.email[0].elementText,        
                psd = user.psd[0].elementText,        
                douban_id = user.douban_id[0].elementText,
                #douban_subject_ids = [int(i) for i in user.douban_subject_ids[0].elementText.split('*')],
                )

        _user.save()

